#include "QcPickResultView.h"
#include <QResizeEvent>
#include <QFileInfo>
#include <QTreeView>
#include <QHeaderView>
#include <QStyledItemDelegate>
#include "QcPickResultListModel.h"
#include "QcPickResultTreeModel.h"
#include "QcGroupedListView.h"
#include "QcPickResultListItemDelegate.h"
#include "util/QuFile.h"

namespace kPrivate
{
    static Qt::SortOrder toggle(Qt::SortOrder order)
    {
        return order == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
    }
}

QcPickResultView::QcPickResultView(QWidget *parent)
    : QFrame{parent}
{
    treeModel_ = new QcPickResultTreeModel(this);
    listModel_ = new QcPickResultListModel(treeModel_, this);

    listView_ = new QcGroupedListView(this);
    listView_->setModel(listModel_);
    listView_->setItemDelegate(new QcPickResultListItemDelegate);
    listView_->setViewMode(QListView::IconMode); // 始终icon模式
    //listView_->setSpacing(8); // NB：设置该值会导致分组标题条之间的间距过大
    listView_->setResizeMode(QListView::Adjust); // 分组根节点绘制需要，否则根节点不能正常伸展
    listView_->setMovement(QListView::Static); // 禁止移动项目
    listView_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 关闭水平滚动条

    treeView_ = new QTreeView(this);
    treeView_->setModel(treeModel_);
    treeView_->setSortingEnabled(false);
    treeView_->setUniformRowHeights(true);
    treeView_->setColumnWidth(0, 240);
    treeView_->setColumnWidth(1, 120);
    treeView_->setColumnWidth(2, 80);
    treeView_->header()->setSectionResizeMode(3, QHeaderView::Stretch);
    treeView_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 关闭水平滚动条
    treeView_->header()->setSectionsClickable(true);

    setViewMode(k_view_list);

    // 连接dataChagned信号，用以追踪勾选的项目数量和控件大小
    // NB: 由于底层构架treeModel原生，此处只能链接treeModel，不能链接listModel
    connect(treeModel_, &QAbstractItemModel::dataChanged, this,
            [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
            if (topLeft.column() == 0 && std::find(roles.begin(), roles.end(), Qt::CheckStateRole) != roles.end()) {
                on_checkState_changed(topLeft, bottomRight);
            }
        });

    // 同步视图的expand/collaps状态
    connect(listView_, &QcGroupedListView::toggleExpandedState, this, [this](const QModelIndex& index) {
        auto [group, item] = listModel_->groupIndex(index.row());
            Q_ASSERT(group >= 0 && item < 0); // 根节点断言
            auto treeIndex = treeModel_->index(group, 0);
            treeView_->setExpanded(treeIndex, !treeView_->isExpanded(treeIndex));
            listView_->doItemsLayout();
        });
    connect(listView_, &QcGroupedListView::doubleClicked, this, [this](const QModelIndex& index) {
            auto [group, item] = listModel_->groupIndex(index.row());
            if (group >= 0 && item < 0)
                emit listView_->toggleExpandedState(index);

            if (item >= 0)
                QuFile::shellOpen(listModel_->data(index, Qt::UserRole).toString());
        });

    // 排序
    connect(treeView_->header(), &QHeaderView::sectionClicked, this, [this](int logicalIndex){
        sort(logicalIndex, sortOrder());
        });

    // 处理双击事件，调用操作系统接口打开文件
    connect(treeView_, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) {
        if (!treeModel_->isGroupRoot(index))
            QuFile::shellOpen(treeModel_->data(index, Qt::UserRole).toString());
    });
}

void QcPickResultView::resizeEvent(QResizeEvent *event)
{
    treeView_->resize(event->size());
    listView_->resize(event->size());

    QWidget::resizeEvent(event);
}

void QcPickResultView::setViewMode(KeViewMode mode)
{
    if (viewMode_ == mode)
        return;

    bool show = treeView_->isVisible() || listView_->isVisible();
    treeView_->setVisible(show && mode == k_view_list);
    listView_->setVisible(show && mode != k_view_list);

    if (mode == k_view_small_icon)
        listView_->setIconSize(QSize(48, 48));
    else if (mode == k_view_median_icon)
        listView_->setIconSize(QSize(72, 72));
    else if (mode == k_view_large_icon)
        listView_->setIconSize(QSize(96, 96));

    if (listView_->isVisible())
        listView_->doItemsLayout(); // treeView可能改变了expanded状态，此处重新布局进行同步

    viewMode_ = mode;
}


void QcPickResultView::on_checkState_changed(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    if (treeModel_->isGroupRoot(topLeft))
        return; // 忽略根节点的check状态变化

    // 追踪项目的check状态变化
    for (int i = topLeft.row(); i <= bottomRight.row(); i++) {
        auto index = treeModel_->index(i, 0, topLeft.parent());
        auto checkState = treeModel_->data(index, Qt::CheckStateRole);

        QFileInfo fi(treeModel_->data(index, Qt::UserRole).toString());
        if (checkState == Qt::Checked) {
            checkedItemsSize_ += fi.size();
            checkedItemsCount_++;
        }
        else {
            checkedItemsSize_ -= fi.size();
            checkedItemsCount_--;
        }

        Q_ASSERT(checkedItemsCount_ >= 0 && checkedItemsSize_  >= 0);
        emit checkedFilesChanged(checkedItemsCount_, checkedItemsSize_);
    }
}

void QcPickResultView::reset()
{
    checkedItemsCount_ = 0;
    checkedItemsSize_ = 0;

    deleteGroup(-1);

    treeView_->reset();
    listView_->reset();

    showView(false);

    treeView_->header()->setSortIndicatorShown(false);
}

int QcPickResultView::groupCount() const
{
    return listModel_->groupCount();
}

int QcPickResultView::groupSize(int group) const
{
    return listModel_->groupSize(group);
}

int QcPickResultView::itemAmount() const
{
    return listModel_->itemAmount();
}

void QcPickResultView::appendItem(int group, const QString& filePath)
{
    listModel_->appendItem(group, filePath);
}

void QcPickResultView::deleteItem(int group, int item)
{
    listModel_->removeItem(group, item);
}

void QcPickResultView::deleteGroup(int group)
{
    listModel_->removeGroup(group);
}

void QcPickResultView::setItemChecked(int group, int item, bool checked)
{
    auto index = listModel_->index(listModel_->listRow(group, item), 0);
    listModel_->setData(index, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
}

bool QcPickResultView::isItemChecked(int group, int item) const
{
    auto index = listModel_->index(listModel_->listRow(group, item), 0);
    return listModel_->data(index, Qt::CheckStateRole).toInt() == Qt::Checked;
}

bool QcPickResultView::isListRowExpanded(int listRow) const
{
    auto [group, item] = listModel_->groupIndex(listRow);
    return group >= 0 && item < 0 && treeView_->isExpanded(treeModel_->index(group, 0));
}

void QcPickResultView::setListRowExpanded(int listRow, bool expanded)
{
    auto [group, item] = listModel_->groupIndex(listRow);
    Q_ASSERT(group >= 0 && item < 0);

    int count = groupSize(group);
    while (count-- > 0)
        listView_->setRowHidden(listRow++, !expanded);
}

bool QcPickResultView::isListRowVisible(int listRow) const
{
    auto [group, item] = listModel_->groupIndex(listRow);
    if (group < 0 || item < 0)
        return true; // 无分组模式或分组根节点，始终可见

    // 判断group是否展开
    return treeView_->isExpanded(treeModel_->index(group, 0));
}

void QcPickResultView::showView(bool show)
{
    treeView_->setVisible(show && viewMode() == k_view_list);
    listView_->setVisible(show && viewMode() != k_view_list);

    if (show) {
        if (groupCount() > 0) {
            treeView_->expandToDepth(0);
            treeView_->resetIndentation();
        }
        else {
            treeView_->setIndentation(0);
        }
        for (int i = 0; i < groupCount(); i++)
            treeView_->setFirstColumnSpanned(i, QModelIndex(), true);
    }
}

void QcPickResultView::forEachCheckedItem(std::function<void(const QString&)> fn, int groupRemovalSize)
{
    if (groupCount() > 0) { // 分组模式
        // 轮询方式采取逆序，因为可能涉及删除item或group
        for (int i = groupCount() - 1; i >=0; i--) {
            for (int j = groupSize(i) - 1; j >= 0; j--) {
                if (!isItemChecked(i, j))
                    continue;

                auto index = listModel_->index(listModel_->listRow(i, j), 0);
                fn(listModel_->data(index, Qt::UserRole).toString());
                if (groupRemovalSize >= 0)
                    deleteItem(i, j);
            }

            if (groupSize(i) <= groupRemovalSize)
                deleteGroup(i);
            else if (groupRemovalSize >= 0)
                setItemChecked(i, -1, false); // 清除分组根节点的勾选状态
        }
    }
    else { // 不分组模式
        for (int j = itemAmount(); j >= 0; j--) {
            if (!isItemChecked(-1, j))
                continue;

            fn(listModel_->data(listModel_->index(j, 0), Qt::UserRole).toString());
            if (groupRemovalSize >= 0)
                deleteItem(-1, j);
        }
    }

    if (groupRemovalSize >= 0) {
        checkedItemsCount_ = 0;
        checkedItemsSize_ = 0;
        emit checkedFilesChanged(0, 0);
    }
}

void QcPickResultView::sort(int column, Qt::SortOrder order)
{
    treeView_->header()->setSortIndicatorShown(true);
    treeView_->header()->setSortIndicator(column, order);
    listModel_->sort(column, order);
}

int QcPickResultView::sortColumn() const
{
    return treeView_->header()->isSortIndicatorShown() ?
        treeView_->header()->sortIndicatorSection() : -1;
}

Qt::SortOrder QcPickResultView::sortOrder() const
{
    return treeView_->header()->sortIndicatorOrder();
}

void QcPickResultView::setSortOrder(Qt::SortOrder order)
{
    treeView_->header()->setSortIndicator(sortColumn(), order);
}

int QcPickResultView::columnCount() const
{
    return treeModel_->columnCount();
}

QString QcPickResultView::columnName(int col) const
{
    return treeModel_->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
}

bool QcPickResultView::useThumbnail() const
{
    return treeModel_->useThumbnail();
}

void QcPickResultView::setUseThumbnail(bool b)
{
    treeModel_->setUseThumbnail(b);
}

void QcPickResultView::setShowDisplayRole(bool b)
{
    showText_ = b;
    listView_->doItemsLayout();
}
